package com.lonefennec.chameleon.characters;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.RayCastCallback;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.lonefennec.chameleon.ChameleonGame;
import com.lonefennec.chameleon.Physics;

public class Tongue extends Actor
{	
	Texture endTexture;
	Sprite midSprite;
	
	public final Vector2 start = new Vector2();
	public final Vector2 finish = new Vector2();
	
	public static final float MAX_TONGUE_LENGTH = 8;
	
	private boolean grappled = false;
	
	public boolean isGrappled()
	{
		float distToFinish = getTongueEndPos().dst2(finish);
		
		return grappled
				&& distToFinish < 0.01f;
	}
	
	private float extended = 0;
	
	@Override
	public void act(float delta)
	{
		final float EXTEND_SPEED = 10f;
		
		float targetLen2 = finish.cpy().sub(start).len2();
		
		extended += delta * EXTEND_SPEED;
		
		if (Math.pow(extended, 2) > targetLen2)
			extended = (float) Math.sqrt(targetLen2);
	}
	
	public Vector2 getTongueEndPos()
	{
		//return start.cpy().lerp(finish, extended);
		
		return start.cpy().add(finish.cpy().sub(start).nor().mul(extended));
	}
	
	@Override
	public Actor hit(float x, float y)
	{
		return null;
	}
	
	@Override
	public void draw(SpriteBatch batch, float parentAlpha)
	{
		endTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
		midSprite.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
		
		//draw the two ends
		float endOffsetX = Physics.SCREEN_TO_WORLD * -endTexture.getWidth() * 0.5f;
		float endOffsetY = Physics.SCREEN_TO_WORLD * -endTexture.getHeight() * 0.5f;
		
		float endDrawWidth = Physics.SCREEN_TO_WORLD * endTexture.getWidth();
		float endDrawHeight = Physics.SCREEN_TO_WORLD * endTexture.getHeight();
		
		float endDrawX;
		float endDrawY;
		
		endDrawX = start.x + endOffsetX;
		endDrawY = start.y + endOffsetY;
		
		batch.draw(endTexture, endDrawX, endDrawY, endDrawWidth, endDrawHeight);
		
		Vector2 currentEndPos = getTongueEndPos();
		
		endDrawX = currentEndPos.x + endOffsetX;
		endDrawY = currentEndPos.y + endOffsetY;
		
		batch.draw(endTexture, endDrawX, endDrawY, endDrawWidth, endDrawHeight);
		
		//draw the midsection
		Vector2 between = currentEndPos.cpy().sub(start);
		Vector2 midPos = between.cpy().mul(0.5f).add(start);
		
		float midWidth = between.len();
		midPos.x -= midWidth /2;
		midPos.y -= midSprite.getHeight() /2;
		
		midSprite.setOrigin(midWidth / 2, midSprite.getHeight() /2);
		
		midSprite.setBounds(midPos.x, midPos.y, between.len(), midSprite.getHeight());
		
		float adj = finish.x - start.x;
		float opp = finish.y - start.y;
		float angle = (float) Math.atan(opp / adj);
		
		midSprite.setRotation((float) (180 / Math.PI * angle));
		
		midSprite.draw(batch);
	}
	
	public Tongue(Player player, Vector2 mouthPos, Vector2 targetPos)	
	{
		//load assets
		
		String endFileName = "sprites/tongue_end.png";
		String midFileName = "sprites/tongue_mid.png";
		
		ChameleonGame.assets.load(endFileName, Texture.class);
		ChameleonGame.assets.load(midFileName, Texture.class);
		
		ChameleonGame.assets.finishLoading();
		
		endTexture = ChameleonGame.assets.get(endFileName, Texture.class);
		
		Texture midTexture = ChameleonGame.assets.get(midFileName, Texture.class);
		midSprite = new Sprite(midTexture);
		midSprite.setSize(midTexture.getWidth() * Physics.SCREEN_TO_WORLD, midTexture.getHeight() * Physics.SCREEN_TO_WORLD);
		
		//tongue targetting logic
		
		//tongue should actually extend beyond where clicked, to its maximum length
		//also limits tongue to max len
		Vector2 between = targetPos.cpy().sub(mouthPos);
		between.nor().mul(Tongue.MAX_TONGUE_LENGTH);
		targetPos.set(between.add(mouthPos));
		
		class TongueRayCastCallback implements RayCastCallback
		{
			public Vector2 hit = null;
			
			public Vector2 start;
			public Vector2 finish;
			
			@Override
			public float reportRayFixture(Fixture fixture, Vector2 point,
					Vector2 normal, float fraction)
			{
				Object userData = fixture.getBody().getUserData();
				
				if (!(userData instanceof WalkingActor))
				{
					hit = start.cpy().lerp(finish, fraction);
					
					return fraction;
				}
				else
					return -1;
			}
		};
		
		TongueRayCastCallback tongueRayCallback = new TongueRayCastCallback();
		//tongueRayCallback.player = player;
		tongueRayCallback.start = mouthPos;
		tongueRayCallback.finish = targetPos;
		
		Physics.getWorld().rayCast(tongueRayCallback, mouthPos, targetPos);
		
		grappled = tongueRayCallback.hit != null;
		
		//the tongue ends where the ray hits anything (todo: filter by type etc)
		Vector2 tongueEnd = grappled? tongueRayCallback.hit : targetPos;
						
		start.set(mouthPos);
		finish.set(tongueEnd.x, tongueEnd.y);
	}
}
